Skip to content

feat: Login 페이지 구현 및 TextButton / GNB 공통 컴포넌트 구현 (#37) #74

Merged
wkdtnqls0506 merged 14 commits intomainfrom
feature/PRODUCT-50
Jul 9, 2025
Merged

feat: Login 페이지 구현 및 TextButton / GNB 공통 컴포넌트 구현 (#37) #74
wkdtnqls0506 merged 14 commits intomainfrom
feature/PRODUCT-50

Conversation

@wkdtnqls0506
Copy link
Contributor

@wkdtnqls0506 wkdtnqls0506 commented Jul 7, 2025

✅ 이슈 번호

close #37


🪄 작업 내용 (변경 사항)

  • 로그인 페이지 구현 /login
  • TextButton 공통 컴포넌트 구현
  • SubGNB 공통 컴포넌트 구현

📸 스크린샷

Login 페이지

스크린샷 2025-07-07 오후 9 39 15

💡 설명


🗣️ 리뷰어에게 전달 사항

  • 파일이 너무 많아졌는데.. Storybook 패키지 변경 + 이미지 파일들이 많아서 커밋별로 보시는걸 추천드립니다 🙇🏻‍♀️🤗

📍 트러블 슈팅

  • Storybook에서 SVG 파일을 React 컴포넌트처럼 import하려 했으나, Vite 기반에선 객체로만 불러와 원하는 방식으로 동작하지 않았습니다.
  • vite-plugin-svgr 적용 등 여러 방법을 시도했지만 해결되지 않아, SVG 처리를 위해 Storybook을 webpack 기반으로 전환하였습니다...😭
  • webpack에 관한 SVGR 설정 예시는 존재하지만, Vite 기반 문서에는 명확한 가이드가 없어 Vite 기반 문서에는 명확한 가이드가 없어서,,, 쩝.....🫠🫠🫠🫠🫠🫠🫠🫠🫠🫠🫠🫠🫠

Summary by CodeRabbit

  • New Features

    • 새로운 GNB(Global Navigation Bar) 컴포넌트와 TextButton 컴포넌트가 추가되었습니다.
    • 로그인 페이지가 브랜드 스타일로 새롭게 디자인되었습니다.
    • GNB 및 TextButton 컴포넌트의 스토리북 예제가 추가되었습니다.
  • Style

    • 버튼, 텍스트필드, 바텀시트 등 주요 UI 컴포넌트의 단위가 px에서 rem으로 일괄 변경되어 반응형 및 접근성이 개선되었습니다.
    • 글로벌 폰트 사이즈가 rem 단위로 변경되었으며, 버튼 색상 토큰이 추가되었습니다.
  • Refactor

    • 스토리북 환경이 Vite에서 Webpack 기반으로 전환되었습니다.
    • 버튼 컴포넌트에 'custom' variant가 추가되었습니다.
  • Chores

    • 관련 패키지 의존성이 정리 및 업데이트되었습니다.

@wkdtnqls0506 wkdtnqls0506 added the ✨ feature 새로운 기능 추가 label Jul 7, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jul 7, 2025

"""

Walkthrough

로그인 페이지가 완전히 새롭게 디자인되고, 관련 스타일과 UI 컴포넌트(GNB, TextButton 등)가 대거 추가되었습니다. Storybook 설정이 Vite에서 Webpack 기반으로 전환되었고, 스타일 시스템은 rem 단위로 통일되었습니다. 여러 신규 컴포넌트와 스토리북 스토리가 도입되었습니다.

Changes

파일/경로 그룹 변경 요약
.storybook/main.ts, .storybook/preview.ts, .storybook/vitest.setup.ts Storybook 설정이 Vite에서 Webpack으로 전환, Vitest 관련 설정 및 플러그인 제거
package.json Storybook, Vanilla Extract, Vitest 등 관련 패키지 의존성 추가/제거/업데이트
src/app/(auth)/login/page.tsx, src/app/(auth)/login/_styles/Login.css.ts 로그인 페이지 UI 전체 리뉴얼 및 전용 스타일 추가
src/components/ui/GNB/* GNB(Global Navigation Bar) 컴포넌트 및 스타일, 스토리북 스토리 신규 추가
src/components/ui/TextButton/* TextButton 컴포넌트, 스타일, 스토리북 스토리 신규 추가 및 index 파일 생성
src/components/ui/Button/Button.css.ts, Button.tsx Button 스타일 리팩토링(rem 적용, typography 사용), variant에 custom 추가
src/components/ui/BottomSheet/BottomSheet.css.ts, TextField/TextField.css.ts 스타일 내 px 단위를 rem 단위로 일괄 변환
src/styles/reset.css.ts, semantic.css.ts, typography.css.ts 글로벌 스타일: html 폰트사이즈, 버튼 색상 토큰 추가, 타이포그래피 rem 단위로 통일
src/components/ui//.stories.tsx Storybook 타입 임포트 경로를 @storybook/nextjs로 변경, 일부 스토리 내 아이콘 import 등 수정

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant LoginPage
    participant GNB
    participant TextButton
    participant KakaoOAuth

    User->>LoginPage: 페이지 접속
    LoginPage->>GNB: GNB 렌더링(좌측: 없음, 우측: 둘러보기)
    User->>GNB: "둘러보기" 클릭
    GNB->>LoginPage: 홈으로 라우팅
    LoginPage->>TextButton: Kakao 로그인 버튼 렌더링
    User->>TextButton: Kakao 로그인 버튼 클릭
    TextButton->>KakaoOAuth: 로그인 함수 호출
Loading

Assessment against linked issues

Objective (Issue) Addressed Explanation
로그인 페이지 UI 구현 (#37)

Assessment against linked issues: Out-of-scope changes

Code Change (file_path) Explanation
Storybook 설정 Vite→Webpack 전환 및 Vitest 관련 삭제 (.storybook/*, package.json) 로그인 UI 구현과 직접 관련 없는 빌드/테스트 환경 변경입니다.
GNB, TextButton 컴포넌트 및 Storybook 스토리 신규 추가 (src/components/ui/GNB/, TextButton/) 로그인 UI에는 사용되지만, 이슈 내 명시적 요구사항은 아니므로 범위 확장 가능성이 있습니다.
글로벌 스타일 리팩토링 및 rem 단위 통일 (src/styles/*, Button.css.ts 등) 로그인 UI에 간접적으로 영향은 있으나, 이슈 본문에는 명시되지 않은 전역 스타일 변경입니다.

Possibly related PRs

Poem

🐰
로그인 창이 새 옷을 입었네,
GNB와 버튼, 스타일도 새로워졌지!
rem으로 맞춘 세상,
토끼는 춤추며 로그인해~
"둘러보기" 누르면 홈으로 폴짝,
카카오 버튼도 반짝!
오늘도 UI는 한 뼘 더 성장!

"""

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/components/ui/Text/Text.css.ts

Oops! Something went wrong! :(

ESLint: 9.30.1

ESLint couldn't find the plugin "eslint-plugin-react-hooks".

(The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-react-hooks@latest --save-dev

The plugin "eslint-plugin-react-hooks" was referenced from the config file in " » eslint-config-next/core-web-vitals » /node_modules/.pnpm/eslint-config-next@15.3.2_eslint@9.30.1_jiti@1.21.7__typescript@5.8.3/node_modules/eslint-config-next/index.js".

If you still can't figure out the problem, please see https://eslint.org/docs/latest/use/troubleshooting.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6341484 and 81f5b35.

📒 Files selected for processing (1)
  • src/components/ui/Text/Text.css.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/components/ui/Text/Text.css.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: test
  • GitHub Check: storybook-preview
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link

github-actions bot commented Jul 7, 2025

🎨 Storybook Preview: https://685a32a1c0bbd269fdb67af4-nssreoytxh.chromatic.com/
🔗 Chromatic Build: https://www.chromatic.com/build?appId=685a32a1c0bbd269fdb67af4&number=85
🕖 Updated at: 2025년 07월 09일 16시 32분 45초

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (6)
src/components/ui/GNB/SubGNB/SubGNB.tsx (1)

68-89: 조건부 로직 개선 제안

컴포넌트 구현은 전반적으로 잘 되어 있으나, 조건부 className 할당 로직을 더 간단하게 만들 수 있습니다.

다음과 같이 리팩토링하여 가독성을 향상시킬 수 있습니다:

-        className={
-          leftAddon && title && align === "left"
-            ? `${styles.leftWrapper} ${styles.leftWrapperWithMargin}`
-            : styles.leftWrapper
-        }
+        className={`${styles.leftWrapper} ${
+          leftAddon && title && align === "left" ? styles.leftWrapperWithMargin : ""
+        }`}
src/app/(auth)/login/_styles/Login.css.ts (2)

44-57: 그라데이션 오버레이 구현 검토

그라데이션 오버레이가 잘 구현되어 있습니다. 다만 하드코딩된 색상 값들(rgba(255, 245, 214, 0), rgba(255, 246, 218, 1), rgba(255, 255, 255, 1))을 semantic 토큰으로 대체하는 것을 고려해보세요.


91-94: 카카오 버튼 색상 하드코딩

카카오 버튼의 배경색이 하드코딩되어 있습니다. 브랜드 색상이므로 semantic 토큰에 정의하거나 상수로 분리하는 것이 좋겠습니다.

export const kakaoButton = style({
-  backgroundColor: "#FAE300",
+  backgroundColor: semantic.brand.kakao, // 또는 별도 상수로 정의
  gap: "0.8rem",
});
src/components/ui/GNB/SubGNB/SubGNB.css.ts (1)

61-61: 단위 일관성 문제

minWidth: "2.4em"이 다른 곳에서 사용하는 rem 단위와 일관성이 없습니다. "2.4rem"으로 변경하는 것이 좋겠습니다.

export const rightWrapper = style({
-  minWidth: "2.4em",
+  minWidth: "2.4rem",
  display: "flex",
  alignItems: "center",
  justifyContent: "flex-end",
  gap: "1.6rem",
});
src/components/ui/TextButton/TextButton.css.ts (1)

6-6: 스타일 이름 충돌 가능성을 확인해주세요.

src/app/(auth)/login/_styles/Login.css.ts에도 textButton이라는 이름의 스타일이 정의되어 있습니다. 동일한 이름으로 인한 혼란을 방지하기 위해 더 구체적인 이름(예: textButtonRecipe)을 사용하는 것을 고려해보세요.

-export const textButton = recipe({
+export const textButtonRecipe = recipe({
.storybook/main.ts (1)

1-1: ESLint 비활성화가 정말 필요한지 확인해주세요.

파일 전체에 @typescript-eslint/no-explicit-any를 비활성화하는 것보다 필요한 부분에만 제한적으로 적용하는 것이 좋습니다.

ESLint 비활성화를 제거하고 대신 webpack 설정 타입을 개선해보세요:

-/* eslint-disable @typescript-eslint/no-explicit-any */
-import type { StorybookConfig } from "@storybook/nextjs";
+import type { StorybookConfig } from "@storybook/nextjs";
+import type { Configuration } from "webpack";
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 38c77d5 and e9be19a.

⛔ Files ignored due to path filters (9)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • public/images/login-background.png is excluded by !**/*.png
  • public/images/login-house.png is excluded by !**/*.png
  • src/assets/check.svg is excluded by !**/*.svg
  • src/assets/kakao-logo.svg is excluded by !**/*.svg
  • src/assets/korean-orange-logo.svg is excluded by !**/*.svg
  • src/assets/left-arrow.svg is excluded by !**/*.svg
  • src/assets/menu.svg is excluded by !**/*.svg
  • src/assets/search.svg is excluded by !**/*.svg
📒 Files selected for processing (28)
  • .storybook/main.ts (1 hunks)
  • .storybook/preview.ts (1 hunks)
  • .storybook/vitest.setup.ts (0 hunks)
  • package.json (4 hunks)
  • src/app/(auth)/login/_styles/Login.css.ts (1 hunks)
  • src/app/(auth)/login/page.tsx (1 hunks)
  • src/components/ui/Bleed/Bleed.stories.tsx (1 hunks)
  • src/components/ui/BottomSheet/BottomSheet.css.ts (3 hunks)
  • src/components/ui/BottomSheet/BottomSheet.stories.tsx (1 hunks)
  • src/components/ui/Button/Button.css.ts (2 hunks)
  • src/components/ui/Button/Button.stories.tsx (1 hunks)
  • src/components/ui/Button/Button.tsx (1 hunks)
  • src/components/ui/GNB/SubGNB/SubGNB.css.ts (1 hunks)
  • src/components/ui/GNB/SubGNB/SubGNB.stories.tsx (1 hunks)
  • src/components/ui/GNB/SubGNB/SubGNB.tsx (1 hunks)
  • src/components/ui/GNB/SubGNB/index.ts (1 hunks)
  • src/components/ui/Spacer/Spacer.stories.tsx (1 hunks)
  • src/components/ui/Stack/Stack.stories.tsx (1 hunks)
  • src/components/ui/Text/Text.stories.tsx (1 hunks)
  • src/components/ui/TextButton/TextButton.css.ts (1 hunks)
  • src/components/ui/TextButton/TextButton.stories.tsx (1 hunks)
  • src/components/ui/TextButton/TextButton.tsx (1 hunks)
  • src/components/ui/TextButton/index.ts (1 hunks)
  • src/components/ui/TextField/TextField.css.ts (3 hunks)
  • src/components/ui/TextField/TextField.stories.tsx (2 hunks)
  • src/styles/reset.css.ts (1 hunks)
  • src/styles/semantic.css.ts (1 hunks)
  • src/styles/typography.css.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • .storybook/vitest.setup.ts
🧰 Additional context used
📓 Path-based instructions (3)
`{src/app/**/_components/*.{ts,tsx},src/components/**/*.{ts,tsx}}`: 컴포넌트 파일은 PascalCase로 네이밍해야 한다 (예: `Button.tsx`, `DomainLayout.tsx`).

{src/app/**/_components/*.{ts,tsx},src/components/**/*.{ts,tsx}}: 컴포넌트 파일은 PascalCase로 네이밍해야 한다 (예: Button.tsx, DomainLayout.tsx).

📄 Source: CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)

List of files the instruction was applied to:

  • src/components/ui/Text/Text.stories.tsx
  • src/components/ui/BottomSheet/BottomSheet.stories.tsx
  • src/components/ui/Bleed/Bleed.stories.tsx
  • src/components/ui/Spacer/Spacer.stories.tsx
  • src/components/ui/Button/Button.stories.tsx
  • src/components/ui/Stack/Stack.stories.tsx
  • src/components/ui/TextField/TextField.stories.tsx
  • src/components/ui/GNB/SubGNB/index.ts
  • src/components/ui/TextButton/index.ts
  • src/components/ui/TextButton/TextButton.tsx
  • src/components/ui/TextField/TextField.css.ts
  • src/components/ui/Button/Button.css.ts
  • src/components/ui/BottomSheet/BottomSheet.css.ts
  • src/components/ui/GNB/SubGNB/SubGNB.tsx
  • src/components/ui/GNB/SubGNB/SubGNB.stories.tsx
  • src/components/ui/GNB/SubGNB/SubGNB.css.ts
  • src/components/ui/TextButton/TextButton.stories.tsx
  • src/components/ui/Button/Button.tsx
  • src/components/ui/TextButton/TextButton.css.ts
`**/*.css.ts`: vanilla-extract 스타일 파일은 camelCase로, `.css.ts` 확장자를 사용해야 하며, 해당 컴포넌트와 같은 폴더에 배치해야 한다.

**/*.css.ts: vanilla-extract 스타일 파일은 camelCase로, .css.ts 확장자를 사용해야 하며, 해당 컴포넌트와 같은 폴더에 배치해야 한다.

📄 Source: CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)

List of files the instruction was applied to:

  • src/styles/reset.css.ts
  • src/styles/semantic.css.ts
  • src/styles/typography.css.ts
  • src/components/ui/TextField/TextField.css.ts
  • src/components/ui/Button/Button.css.ts
  • src/components/ui/BottomSheet/BottomSheet.css.ts
  • src/app/(auth)/login/_styles/Login.css.ts
  • src/components/ui/GNB/SubGNB/SubGNB.css.ts
  • src/components/ui/TextButton/TextButton.css.ts
`src/styles/*`: 전역 스타일 파일은 `styles/` 폴더에 위치해야 한다.

src/styles/*: 전역 스타일 파일은 styles/ 폴더에 위치해야 한다.

📄 Source: CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)

List of files the instruction was applied to:

  • src/styles/reset.css.ts
  • src/styles/semantic.css.ts
  • src/styles/typography.css.ts
🧠 Learnings (14)
.storybook/preview.ts (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to middleware.ts : Next.js 미들웨어는 프로젝트 루트의 `middleware.ts`로 관리해야 한다.
src/components/ui/Bleed/Bleed.stories.tsx (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to middleware.ts : Next.js 미들웨어는 프로젝트 루트의 `middleware.ts`로 관리해야 한다.
src/styles/reset.css.ts (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to src/styles/* : 전역 스타일 파일은 `styles/` 폴더에 위치해야 한다.
src/components/ui/Spacer/Spacer.stories.tsx (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to middleware.ts : Next.js 미들웨어는 프로젝트 루트의 `middleware.ts`로 관리해야 한다.
src/components/ui/Button/Button.stories.tsx (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to {src/app/**/_components/*.{ts,tsx},src/components/**/*.{ts,tsx}} : 컴포넌트 파일은 PascalCase로 네이밍해야 한다 (예: `Button.tsx`, `DomainLayout.tsx`).
src/components/ui/Stack/Stack.stories.tsx (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to middleware.ts : Next.js 미들웨어는 프로젝트 루트의 `middleware.ts`로 관리해야 한다.
src/components/ui/TextButton/index.ts (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to {src/app/**/_components/*.{ts,tsx},src/components/**/*.{ts,tsx}} : 컴포넌트 파일은 PascalCase로 네이밍해야 한다 (예: `Button.tsx`, `DomainLayout.tsx`).
src/components/ui/TextButton/TextButton.tsx (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to {src/app/**/_components/*.{ts,tsx},src/components/**/*.{ts,tsx}} : 컴포넌트 파일은 PascalCase로 네이밍해야 한다 (예: `Button.tsx`, `DomainLayout.tsx`).
src/app/(auth)/login/page.tsx (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to {src/app/**/_components/*.{ts,tsx},src/components/**/*.{ts,tsx}} : 컴포넌트 파일은 PascalCase로 네이밍해야 한다 (예: `Button.tsx`, `DomainLayout.tsx`).
src/app/(auth)/login/_styles/Login.css.ts (2)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to **/*.css.ts : vanilla-extract 스타일 파일은 camelCase로, `.css.ts` 확장자를 사용해야 하며, 해당 컴포넌트와 같은 폴더에 배치해야 한다.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: 스타일 근접성: vanilla-extract 스타일 파일은 해당 컴포넌트와 같은 폴더에 배치해야 한다.
src/components/ui/GNB/SubGNB/SubGNB.css.ts (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to **/*.css.ts : vanilla-extract 스타일 파일은 camelCase로, `.css.ts` 확장자를 사용해야 하며, 해당 컴포넌트와 같은 폴더에 배치해야 한다.
src/components/ui/TextButton/TextButton.stories.tsx (1)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to {src/app/**/_components/*.{ts,tsx},src/components/**/*.{ts,tsx}} : 컴포넌트 파일은 PascalCase로 네이밍해야 한다 (예: `Button.tsx`, `DomainLayout.tsx`).
.storybook/main.ts (3)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to next.config.js : Next.js 설정 파일은 프로젝트 루트의 `next.config.js`로 관리해야 한다.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to **/*.css.ts : vanilla-extract 스타일 파일은 camelCase로, `.css.ts` 확장자를 사용해야 하며, 해당 컴포넌트와 같은 폴더에 배치해야 한다.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to middleware.ts : Next.js 미들웨어는 프로젝트 루트의 `middleware.ts`로 관리해야 한다.
src/components/ui/TextButton/TextButton.css.ts (2)
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to **/*.css.ts : vanilla-extract 스타일 파일은 camelCase로, `.css.ts` 확장자를 사용해야 하며, 해당 컴포넌트와 같은 폴더에 배치해야 한다.
Learnt from: CR
PR: YAPP-Github/26th-Web-Team-1-FE#0
File: .cursor/rules/nextjs-folder-structure.mdc:0-0
Timestamp: 2025-06-30T08:25:30.684Z
Learning: Applies to {src/app/**/_components/*.{ts,tsx},src/components/**/*.{ts,tsx}} : 컴포넌트 파일은 PascalCase로 네이밍해야 한다 (예: `Button.tsx`, `DomainLayout.tsx`).
🧬 Code Graph Analysis (6)
src/app/(auth)/login/page.tsx (1)
src/app/(auth)/_api/auth/auth.api.ts (1)
  • redirectToKakaoOAuthLoginPage (42-44)
src/components/ui/Button/Button.css.ts (1)
src/styles/typography.css.ts (1)
  • typography (3-148)
src/components/ui/BottomSheet/BottomSheet.css.ts (2)
src/styles/typography.css.ts (1)
  • typography (3-148)
src/styles/semantic.css.ts (1)
  • semantic (5-68)
src/components/ui/GNB/SubGNB/SubGNB.tsx (2)
src/components/ui/GNB/SubGNB/index.ts (2)
  • SubGNBProps (1-1)
  • SubGNB (1-1)
src/components/ui/GNB/SubGNB/SubGNB.css.ts (1)
  • title (53-58)
src/components/ui/TextButton/TextButton.stories.tsx (2)
src/components/ui/TextButton/TextButton.tsx (1)
  • TextButton (28-46)
src/components/ui/TextButton/index.ts (1)
  • TextButton (1-1)
src/components/ui/TextButton/TextButton.css.ts (1)
src/app/(auth)/login/_styles/Login.css.ts (1)
  • textButton (25-27)
🪛 GitHub Actions: Storybook Chromatic Deployment
src/components/ui/TextField/TextField.stories.tsx

[error] 1-1: Build failed: Module not found error - Can't resolve '@/assets/clear.svg'. This caused the Storybook build to fail with exit code 1.

src/components/ui/TextField/TextField.css.ts

[error] 1-1: Build failed: Module not found error - Can't resolve '@/assets/clear.svg'. This caused the Storybook build to fail with exit code 1.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (41)
src/styles/reset.css.ts (1)

5-7: rem 단위 시스템을 위한 적절한 기본 설정입니다.

HTML 요소에 fontSize: "62.5%"를 설정하는 것은 rem 단위 계산을 쉽게 하기 위한 표준 방법입니다 (1rem = 10px). 이는 typography.css.ts의 rem 단위 변환과 완벽하게 일치합니다.

src/styles/semantic.css.ts (1)

18-29: 버튼 컴포넌트를 위한 체계적인 색상 토큰 구성입니다.

버튼 관련 시맨틱 색상들을 별도 섹션으로 구성하여 일관성을 높였습니다. 네이밍 컨벤션(primaryNormalSolid, textPrimary 등)이 직관적이고 기존 색상 토큰 구조와 잘 맞습니다.

src/styles/typography.css.ts (1)

5-6: rem 단위 시스템으로의 일관된 변환입니다.

모든 타이포그래피 토큰이 px에서 rem 단위로 정확하게 변환되었습니다. 이는 reset.css.ts의 기본 폰트 크기 설정과 완벽하게 일치하며, 반응형 디자인과 접근성 향상에 도움이 됩니다.

src/components/ui/BottomSheet/BottomSheet.stories.tsx (1)

1-1: Storybook 프레임워크 마이그레이션에 따른 올바른 import 변경입니다.

Vite에서 Webpack 기반 Storybook으로의 마이그레이션에 맞춰 import 경로가 정확하게 업데이트되었습니다.

src/components/ui/Text/Text.stories.tsx (1)

1-1: 일관된 Storybook 마이그레이션 적용입니다.

모든 Storybook 파일에서 일관되게 적용된 import 변경으로, Webpack 기반 Storybook 설정과 완벽히 호환됩니다.

src/components/ui/Spacer/Spacer.stories.tsx (1)

1-1: Storybook 타입 import 경로 전환 확인 완료
Vite → Webpack 마이그레이션에 따라 "@storybook/nextjs" 사용이 맞습니다. 다른 변경 사항 없이 정상 동작할 것으로 보입니다.

남아 있을 수 있는 @storybook/nextjs-vite 의존성 및 임포트가 더 없는지 한번 rg 검색으로 확인해 주세요.

src/components/ui/Stack/Stack.stories.tsx (1)

1-1: import 경로 수정 OK
Webpack 기반 설정과 일치합니다. 추가 조치 필요 없습니다.

.storybook/preview.ts (1)

3-3: Preview 타입 import 경로 변경 확인
@storybook/nextjs 로의 단일 변경이며, 나머지 설정과 충돌되지 않습니다.

src/components/ui/Bleed/Bleed.stories.tsx (1)

1-1: 경로 업데이트 적절
Bleed 스토리 또한 동일하게 변경되었습니다. 일관성 유지 👍

src/components/ui/Button/Button.stories.tsx (1)

1-1: Button 스토리북 import 경로 교체 완료
모듈 전환에 따른 필수 변경으로 보이며, 문제 없습니다.

src/components/ui/GNB/SubGNB/index.ts (1)

1-1: 표준적인 컴포넌트 export 패턴을 잘 따르고 있습니다.

SubGNB 컴포넌트와 타입을 깔끔하게 re-export하는 구조로, 다른 파일에서 import하기 쉽도록 설계되었습니다.

src/components/ui/TextButton/index.ts (1)

1-1: 일관된 컴포넌트 export 구조를 유지하고 있습니다.

다른 UI 컴포넌트들과 동일한 패턴으로 구현되어 코드베이스의 일관성을 유지하고 있습니다.

src/components/ui/TextField/TextField.stories.tsx (2)

1-1: Storybook 설정 변경이 올바르게 반영되었습니다.

Webpack 기반 Storybook 설정으로의 전환에 맞춰 import 경로가 정확히 업데이트되었습니다.


50-50: 조건부 렌더링 로직이 올바르게 구현되었습니다.

입력값이 있고 비활성화 상태가 아닐 때만 ClearIcon을 표시하는 로직이 적절합니다.

src/components/ui/TextField/TextField.css.ts (3)

9-9: rem 단위 사용으로 스타일 시스템이 개선되었습니다.

픽셀 단위에서 rem 단위로의 변경은 확장성과 접근성을 향상시킵니다.


20-21: 입력 필드의 크기와 패딩이 일관되게 업데이트되었습니다.

높이와 패딩 값이 rem 단위로 변경되어 전체 디자인 시스템과 일관성을 유지합니다.


86-86: 우측 애드온 위치와 패딩이 적절히 조정되었습니다.

right 위치와 padding 값이 rem 단위로 변경되어 전체 스타일 시스템과 일관성을 유지합니다.

Also applies to: 91-91

src/components/ui/Button/Button.css.ts (3)

3-3: typography 토큰 import 추가 승인

디자인 시스템 일관성을 위한 typography 토큰 import가 적절하게 추가되었습니다.


42-42: custom variant 추가 승인

custom variant의 빈 객체 추가로 유연한 커스터마이징이 가능해졌습니다. TextButton 컴포넌트와의 일관성도 유지되었습니다.


46-47: typography 토큰 및 rem 단위 적용 승인

typography 토큰을 활용한 일관된 폰트 스타일링과 rem 단위 변환이 적절하게 적용되었습니다. 이는 디자인 시스템의 일관성과 접근성을 향상시킵니다.

Also applies to: 51-52, 56-57, 61-63

src/components/ui/BottomSheet/BottomSheet.css.ts (1)

16-16: rem 단위 변환 승인

px에서 rem으로의 단위 변환이 일관되게 적용되었습니다. 이는 반응형 디자인과 접근성 향상에 도움이 됩니다. 변환 비율도 올바르게 적용되었습니다.

Also applies to: 27-27, 34-34, 38-39, 42-42, 47-48, 56-57, 72-72

src/components/ui/TextButton/TextButton.tsx (3)

1-13: 타입 정의 및 import 승인

TypeScript 타입 정의가 적절하게 구성되었으며, ComponentProps<"button">을 활용한 props 확장이 올바르게 구현되었습니다.


15-26: JSDoc 문서화 승인

컴포넌트의 용도와 사용법이 명확하게 문서화되어 있으며, 실제 사용 예시도 포함되어 있어 개발자 경험을 향상시킵니다.


28-46: 컴포넌트 구현 승인

props 기본값 설정, 조건부 렌더링, className 조합 등이 올바르게 구현되었습니다. leftAddon의 span 래핑과 children의 span 래핑도 일관성 있게 처리되었습니다.

src/app/(auth)/login/page.tsx (3)

3-4: Next.js 패턴 적용 승인

Next.js의 Image 컴포넌트와 useRouter 훅을 적절하게 활용하여 성능과 네비게이션을 올바르게 구현했습니다.

Also applies to: 16-16


6-13: 컴포넌트 및 asset import 승인

새로운 UI 컴포넌트들과 SVG asset들이 적절하게 import되어 있으며, 모듈 구조가 깔끔하게 정리되어 있습니다.


22-79: 로그인 페이지 UI 구현 승인

SubGNB, TextButton, Button 등의 새로운 컴포넌트들을 활용한 로그인 페이지 구현이 잘 되어 있습니다. 레이아웃 구조가 논리적이며, 한국어 텍스트와 카카오 로그인 연동도 적절하게 구현되었습니다.

src/components/ui/GNB/SubGNB/SubGNB.tsx (2)

1-35: 타입 정의 및 Props 인터페이스 승인

AlignVariant와 WrapperVariants 타입 정의가 명확하며, SubGNBProps 인터페이스가 잘 구조화되어 있습니다. JSDoc 주석도 각 prop의 용도를 명확히 설명하고 있습니다.


37-58: JSDoc 문서화 승인

컴포넌트의 용도와 사용법이 상세하게 문서화되어 있으며, 실제 사용 예시가 포함되어 개발자 경험을 크게 향상시킵니다.

package.json (3)

26-26: ky 패키지 버전 다운그레이드 확인 필요

ky 패키지가 이전 버전으로 다운그레이드되었습니다. 이것이 의도된 변경인지, 특정 호환성 문제로 인한 것인지 확인이 필요합니다.


43-43: Storybook Webpack 마이그레이션 잘 적용됨

Vite에서 Webpack 기반 Storybook으로의 마이그레이션이 package.json에 올바르게 반영되었습니다. 이는 SVG 컴포넌트 임포트 문제 해결을 위한 변경사항과 일치합니다.


56-57: vanilla-extract 플러그인 전환 확인

vanilla-extract 플러그인이 Vite에서 Webpack으로 올바르게 전환되었습니다. 이는 전체 마이그레이션 전략과 일치합니다.

src/components/ui/GNB/SubGNB/SubGNB.stories.tsx (3)

1-7: SVG 컴포넌트 임포트 성공적으로 작동

SVG 파일들이 React 컴포넌트로 성공적으로 임포트되고 있습니다. 이는 Webpack 마이그레이션이 SVG 처리 문제를 해결했음을 확인해줍니다.


9-45: 포괄적인 Storybook 설정

argTypes 설정이 매우 상세하고 각 prop에 대한 설명이 명확합니다. 특히 leftAddonrightAddon의 control을 false로 설정한 것은 React 엘리먼트 특성상 적절한 선택입니다.


47-193: 다양한 사용 사례를 보여주는 스토리들

SubGNB 컴포넌트의 다양한 사용 사례를 체계적으로 보여주는 스토리들이 잘 구성되어 있습니다. 각 스토리마다 명확한 문서화도 포함되어 있습니다.

src/app/(auth)/login/_styles/Login.css.ts (1)

1-4: 적절한 스타일 토큰 사용

semantic과 typography 토큰을 올바르게 임포트하여 일관된 디자인 시스템을 유지하고 있습니다.

src/components/ui/GNB/SubGNB/SubGNB.css.ts (1)

6-26: vanilla-extract recipe 잘 활용됨

recipe를 사용하여 background 변형을 깔끔하게 구현했습니다. 기본값 설정도 적절합니다.

src/components/ui/TextButton/TextButton.stories.tsx (3)

1-5: SVG 컴포넌트 임포트 성공

SVG 파일이 React 컴포넌트로 성공적으로 임포트되고 있어 Webpack 마이그레이션이 올바르게 작동함을 확인할 수 있습니다.


77-91: Custom variant 스토리 설명 훌륭함

Custom variant의 용도에 대한 설명이 명확합니다. 이는 개발자들이 언제 custom variant를 사용해야 하는지 이해하는 데 도움이 됩니다.


108-122: leftAddon 사용 예시 적절함

leftAddon props의 사용 예시가 명확하고 실용적입니다. 아이콘 크기(20x20)도 적절합니다.

src/components/ui/TextButton/TextButton.css.ts (1)

1-52: 전반적으로 잘 구현되었습니다!

vanilla-extract의 recipe 패턴을 활용하여 변형(variant)과 크기(size) 옵션을 깔끔하게 구현하셨네요. 스타일 파일의 위치와 네이밍 규칙도 잘 지켜주셨습니다.

import { button } from "./Button.css";

type ButtonVariant = "primary" | "dark" | "assistive";
type ButtonVariant = "primary" | "dark" | "assistive" | "custom";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

"custom" 변형이 추가되었습니다. 해당 스타일 구현을 확인해 주세요.

ButtonVariant 타입에 "custom" 변형이 올바르게 추가되었습니다. Button.css.ts에 해당 스타일이 구현되어 있는지 확인이 필요합니다.

다음 스크립트를 실행하여 custom 변형 스타일이 구현되어 있는지 확인해 주세요:


🏁 Script executed:

#!/bin/bash
# custom 변형 스타일 구현 확인
rg -A 10 "custom" src/components/ui/Button/Button.css.ts

Length of output: 292


Button.css.ts에 custom 변형 스타일 내용 추가 필요

src/components/ui/Button/Button.css.ts의 custom 키는 이미 정의되어 있지만, 현재 빈 객체로 스타일이 구현되어 있지 않습니다. 아래 위치에 원하는 스타일 속성(색상, 배경, 폰트 등)을 추가해 주세요.

• 파일: src/components/ui/Button/Button.css.ts
• 위치:

variant: {
  
  custom: {},  // 여기에 스타일 속성 추가 필요
},
🤖 Prompt for AI Agents
In src/components/ui/Button/Button.tsx at line 5, the ButtonVariant type
includes "custom", but in src/components/ui/Button/Button.css.ts, the "custom"
variant is defined as an empty object. To fix this, open
src/components/ui/Button/Button.css.ts and add the desired CSS style properties
(such as color, background, font) inside the "custom" key within the variant
object to properly style the custom button variant.

import type { Meta, StoryObj } from "@storybook/nextjs";
import { type ComponentProps } from "react";

import ClearIcon from "@/assets/clear.svg";
Copy link

@coderabbitai coderabbitai bot Jul 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

SVG 파일 경로를 확인해 주세요.

ClearIcon import가 활성화되었지만 파이프라인에서 '@/assets/clear.svg' 파일을 찾을 수 없다는 오류가 발생하고 있습니다.

다음 스크립트를 실행하여 SVG 파일 존재 여부와 경로 별칭 설정을 확인해 주세요:


🏁 Script executed:

#!/bin/bash
# SVG 파일 존재 여부 확인
echo "=== SVG 파일 찾기 ==="
fd -e svg clear

echo "=== assets 폴더 구조 확인 ==="
fd -t d assets

echo "=== 경로 별칭 설정 확인 ==="
cat tsconfig.json | jq '.compilerOptions.paths'

Length of output: 299


SVG 파일 경로 대소문자 불일치 수정 필요

TextField 스토리에서 ClearIcon을 import할 때 실제 파일명은 src/assets/Clear.svg인데, 코드에서는 clear.svg로 소문자 경로를 사용하여 빌드 오류가 발생하고 있습니다. import 구문을 다음과 같이 수정해 주세요:

- import ClearIcon from "@/assets/clear.svg";
+ import ClearIcon from "@/assets/Clear.svg";
  • 파일 위치: src/components/ui/TextField/TextField.stories.tsx (4번째 줄)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import ClearIcon from "@/assets/clear.svg";
-import ClearIcon from "@/assets/clear.svg";
+import ClearIcon from "@/assets/Clear.svg";
🤖 Prompt for AI Agents
In src/components/ui/TextField/TextField.stories.tsx at line 4, the import
statement for ClearIcon uses an incorrect lowercase file path 'clear.svg' which
does not match the actual file name 'Clear.svg'. Update the import path to use
the correct case-sensitive filename 'Clear.svg' to resolve the build error.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wkdtnqls0506 수빈님 요것 때문에 스토리북 실행이 안 돼요! 나중에 수정 부탁드립니다!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3db2cdc

아이코 수정했습니다 🤗

Comment on lines +16 to 37
webpackFinal: async (config: any) => {
const imageRule = config.module.rules.find(rule => {
const test = (rule as { test: RegExp }).test;

if (!test) {
return false;
}

return test.test(".svg");
}) as { [key: string]: any };

imageRule.exclude = /\.svg$/;

config.module.rules.push({
test: /\.svg$/,
use: ["@svgr/webpack"],
});

config.plugins.push(new VanillaExtractPlugin());

return config;
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

타입 안전성을 개선해주세요.

webpack 설정에서 any 타입을 과도하게 사용하고 있습니다. 더 명확한 타입을 사용하면 유지보수성이 향상됩니다.

-  webpackFinal: async (config: any) => {
-    const imageRule = config.module.rules.find(rule => {
-      const test = (rule as { test: RegExp }).test;
+  webpackFinal: async (config: Configuration) => {
+    const imageRule = config.module?.rules?.find(rule => {
+      if (typeof rule === "object" && rule !== null && "test" in rule) {
+        const test = rule.test;

그리고 타입 가드를 사용하여 안전하게 처리하세요:

-    }) as { [key: string]: any };
+    });

-    imageRule.exclude = /\.svg$/;
+    if (imageRule && typeof imageRule === "object") {
+      imageRule.exclude = /\.svg$/;
+    }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In .storybook/main.ts around lines 16 to 37, the webpackFinal function uses
'any' type for the config parameter and casts rules unsafely. Replace 'any' with
the appropriate Webpack Configuration type from '@storybook/core-common' or
'webpack' packages. Use type guards to check if rule.test exists and is a RegExp
before calling test.test(".svg"). This will improve type safety and
maintainability.

Copy link
Member

@Seojunhwan Seojunhwan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수빈님! 몇가지 의견 슥삭 남겨두었습니다!

import type { Meta, StoryObj } from "@storybook/nextjs";
import { type ComponentProps } from "react";

import ClearIcon from "@/assets/clear.svg";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wkdtnqls0506 수빈님 요것 때문에 스토리북 실행이 안 돼요! 나중에 수정 부탁드립니다!

Comment on lines 60 to 90
export const SubGNB = ({
title,
align = "center",
leftAddon,
rightAddon,
background,
}: SubGNBProps) => {
return (
<header className={styles.wrapper({ background })}>
<div
className={
leftAddon && title && align === "left"
? `${styles.leftWrapper} ${styles.leftWrapperWithMargin}`
: styles.leftWrapper
}
>
{leftAddon}
</div>
<div
className={
align === "center"
? styles.titleWrapperCenter
: styles.titleWrapperLeft
}
>
{title && <h1 className={styles.title}>{title}</h1>}
</div>
<div className={styles.rightWrapper}>{rightAddon}</div>
</header>
);
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

P3: 타이틀 가운데 정렬이 틀어질 수도 있을 것 같은데 요것 확인 부탁드려요!
측정했을 때 왼쪽 여백이 424, 오른쪽 여백이 460?,, 이었나 했던 것 같아요

(left, right를 absolute로 처리해야하나?,,)

ASK: 혹시 main_gnb와 동일하다면 네이밍을 변경해서 함께 사용해보는 것은 어떨까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. 쓰읍.. flex로 최대한 가운데 정렬을 맞춰보려고 했는데 들어가는 아이콘 개수나 width 차이에 따라 타이틀이 틀어질 수 있겠네요.. 아니면 타이틀을 absolute로 가운데 정렬 맞춰주는 것도 괜찮을 거 같아요!
스크린샷 2025-07-09 오전 12 41 01
  1. 아얀님께 여쭤보니까 main_gnb와 차이점이 타이틀이 텍스트냐 / 아이콘이냐의 차이점이라구 하시네요! 하나로 가져가도 좋을 거 같습니다 ㅎㅎ 수정하고 알려드릴게요!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

caad43c

2개 모두 수정사항 반영헸습니다~!

import { button } from "./Button.css";

type ButtonVariant = "primary" | "dark" | "assistive";
type ButtonVariant = "primary" | "dark" | "assistive" | "custom";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ASK: custom은 어떤 용도인지 알 수 있을까요?!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기존 variant 스타일을 덮어쓰기보단 custom으로 초기화 후 원하는 스타일만 적용하는게 깔끔하다고 생각해서 사용했습니다!

position: "relative",
width: "100%",
height: "100%",
backgroundImage: "url(\"/images/login-background.png\")",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Next.js Image를 사용하는 방법은 어떨까요?! 혹은 css backgroundImage를 사용할 경우 해당 이미지를 tinypng같은 곳에서 압축 + webp로 변환하여 제공해보아도 좋을 것 같아요! (1.54mb 짜리라,,)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9faffbd

webp로 변환하여 28.1 KB로 줄였습니다~!

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/components/ui/GNB/GNB.tsx (1)

67-94: 조건부 스타일링 로직을 개선할 수 있습니다.

현재 조건부 스타일링 로직이 복잡하여 가독성이 떨어집니다. 더 명확한 방식으로 개선할 수 있습니다.

다음과 같이 리팩토링을 고려해보세요:

export const GNB = ({
  title,
  align = "center",
  leftAddon,
  rightAddon,
  background = "white",
}: GNBProps) => {
+  const shouldAddLeftMargin = leftAddon && title && align === "left";
+  const leftWrapperClassName = shouldAddLeftMargin 
+    ? `${styles.leftWrapper} ${styles.leftWrapperWithMargin}`
+    : styles.leftWrapper;
+  
+  const titleWrapperClassName = align === "center"
+    ? styles.titleWrapperAbsoluteCenter
+    : styles.titleWrapperLeft;

  return (
    <header className={styles.wrapper({ background })}>
-      <div
-        className={
-          leftAddon && title && align === "left"
-            ? `${styles.leftWrapper} ${styles.leftWrapperWithMargin}`
-            : styles.leftWrapper
-        }
-      >
+      <div className={leftWrapperClassName}>
        {leftAddon}
      </div>

      {title && (
-        <div
-          className={
-            align === "center"
-              ? styles.titleWrapperAbsoluteCenter
-              : styles.titleWrapperLeft
-          }
-        >
+        <div className={titleWrapperClassName}>
          <span className={styles.title}>{title}</span>
        </div>
      )}

      <div className={styles.rightWrapper}>{rightAddon}</div>
    </header>
  );
};
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e9be19a and caad43c.

⛔ Files ignored due to path filters (1)
  • src/assets/circle-clear.svg is excluded by !**/*.svg
📒 Files selected for processing (5)
  • src/components/ui/GNB/GNB.css.ts (1 hunks)
  • src/components/ui/GNB/GNB.stories.tsx (1 hunks)
  • src/components/ui/GNB/GNB.tsx (1 hunks)
  • src/components/ui/GNB/index.ts (1 hunks)
  • src/components/ui/TextField/TextField.stories.tsx (2 hunks)
✅ Files skipped from review due to trivial changes (3)
  • src/components/ui/GNB/index.ts
  • src/components/ui/GNB/GNB.css.ts
  • src/components/ui/GNB/GNB.stories.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/ui/TextField/TextField.stories.tsx
🧰 Additional context used
📓 Path-based instructions (1)
`{src/app/**/_components/*.{ts,tsx},src/components/**/*.{ts,tsx}}`: 컴포넌트 파일은 PascalCase로 네이밍해야 한다 (예: `Button.tsx`, `DomainLayout.tsx`).

{src/app/**/_components/*.{ts,tsx},src/components/**/*.{ts,tsx}}: 컴포넌트 파일은 PascalCase로 네이밍해야 한다 (예: Button.tsx, DomainLayout.tsx).

📄 Source: CodeRabbit Inference Engine (.cursor/rules/nextjs-folder-structure.mdc)

List of files the instruction was applied to:

  • src/components/ui/GNB/GNB.tsx
🧬 Code Graph Analysis (1)
src/components/ui/GNB/GNB.tsx (2)
src/components/ui/GNB/index.ts (1)
  • GNB (1-1)
src/components/ui/GNB/GNB.css.ts (1)
  • title (57-64)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (2)
src/components/ui/GNB/GNB.tsx (2)

5-6: 타입 정의가 명확하고 적절합니다.

타입 정의가 명확하고 사용 목적에 부합합니다.


8-35: Props 인터페이스가 잘 구성되어 있습니다.

Props 타입 정의가 명확하고 JSDoc 주석이 상세합니다. 모든 props가 optional로 설정되어 유연성을 제공합니다.

@wkdtnqls0506 wkdtnqls0506 changed the title feat: Login 페이지 구현 및 TextButton/SubGNB 공통 컴포넌트 구현 (#37) feat: Login 페이지 구현 및 TextButton / GNB 공통 컴포넌트 구현 (#37) Jul 9, 2025
Copy link
Member

@Seojunhwan Seojunhwan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아이코 제가 놓친 부분까지 잘 챙겨주셨군요! 고생하셨어요!

@wkdtnqls0506 wkdtnqls0506 merged commit dc289db into main Jul 9, 2025
6 checks passed
@wkdtnqls0506 wkdtnqls0506 deleted the feature/PRODUCT-50 branch July 9, 2025 13:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ feature 새로운 기능 추가

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[PRODUCT-50] 로그인 페이지 UI 구현

2 participants